﻿//
// © Algobox Ltd - Benn Eichhorn
//
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Collections.Concurrent;
using Algobox.Objects.Finance.Assets.Stock;
using Algobox.Objects.Finance;
using Algobox.Toolbox.Collections;
using Algobox.Structure.Finance.Strategies.SmartStoploss;
using System.Windows.Data;

namespace Algobox.Structure.Finance.Strategies.SpikeArb
{
    public class SpikeArbManagement
    {
        #region Constructors

        public SpikeArbManagement(Algobox.Feeds.Finance.MarketData.IMarketFeedAdaptor marketFeed,
            Algobox.Feeds.Finance.Trading.ITradingFeedAdaptor tradingFeed,
            SmartStoplossManagement stoplossManager)
        {
            MarketFeed = marketFeed;
            TradingFeed = tradingFeed;
            StoplossManager = stoplossManager;
                                    
            Strategies = new ConcurrentDictionary<StockSecurity, SpikeArbStock>();
            
            _account = "LQA001";

            _timerExitAll = new System.Threading.Timer(new System.Threading.TimerCallback(StopStrategy), this, TIME_EXIT_ALL, TimeSpan.FromMilliseconds(-1));
        }

        #endregion
        //////////
        #region Member Variables
        
        public readonly static TimeSpan TIME_EXIT_ALL = TimeSpan.FromHours(16.48); // 16:28:48

        System.Threading.Timer _timerExitAll;

        public static string _account;

        /// <summary>
        /// minimum percentage collar is allowed to be set to or price of collar is allowed to be away from the bid or ask
        /// </summary>
        public const double MIN_COLLAR_PERCENTAGE = 0.1;
        
        /// <summary>
        /// maximum percentage collar is allowed to be set to or price of collar is allowed to be away from the last
        /// </summary>
        public const double MAX_COLLAR_PERCENTAGE = 4.8;

        /// <summary>
        /// Minimum value of collar
        /// </summary>
        public const double MIN_COLLAR_VALUE = 40;

        /// <summary>
        /// Maximum value of collar
        /// </summary>
        public const double MAX_COLLAR_VALUE = 15000;

        public const SpikeArbStock.ExitPercentages DEFAULT_EXIT_PERCENTAGE = SpikeArbStock.ExitPercentages.P100_070;
        
        /// <summary>
        /// Logger used by this class
        /// </summary>        
        private static readonly NLog.Logger Log = NLog.LogManager.GetCurrentClassLogger();

        private List<SpikeArbFill> _executions;

        #endregion
        //////////
        #region Properties

        public static string Account { get { return _account; } set { if(value != null && value != String.Empty) _account = value; } }

        public bool IsLoaded { get; private set; }
        public bool IsStarted { get; private set; }

        public ConcurrentObservableDictionary<string, SpikeArbStockView> ViewSettings { get; set; }
        public ListCollectionView ViewExecutions { get; set; }

        public ConcurrentDictionary<StockSecurity, SpikeArbStock> Strategies { get; private set; }
        public Algobox.Feeds.Finance.MarketData.IMarketFeedAdaptor MarketFeed { get; private set; }
        public Algobox.Feeds.Finance.Trading.ITradingFeedAdaptor TradingFeed { get; private set; }
        public SmartStoplossManagement StoplossManager { get; private set; }
        
        #endregion
        //////////
        #region Functions

        /// <summary>
        /// Creates or updates SpikeArb stock and collars and submits the strategy for management and viewing
        /// </summary>
         /// <returns></returns>
        public SpikeArbStock AddOrUpdate(int id, StockSecurity stock,
            bool isEnabledPrimary, bool isEnabledChix, bool isEnabledBATE,
            bool collar1Enabled, decimal collar1Value, decimal collar1Percent, decimal collar1Window,
            bool collar2Enabled, decimal collar2Value, decimal collar2Percent, decimal collar2Window,
            bool collar3Enabled, decimal collar3Value, decimal collar3Percent, decimal collar3Window,
            bool collar4Enabled, decimal collar4Value, decimal collar4Percent, decimal collar4Window)
        {
            Log.Info("Creating SpikeArbStock {0}", stock);
            
            // create or update the strategy and add it to the manager dictionary
            SpikeArbStock strategy = Strategies.AddOrUpdate(stock,
                (inStock) =>
                {
                    strategy = new SpikeArbStock(this, id, stock);

                    strategy.ListingPrimary.IsEnabled = isEnabledPrimary;
                    strategy.ListingChix.IsEnabled = isEnabledChix;
                    strategy.ListingBats.IsEnabled = isEnabledBATE;

                    strategy.SetCollar(SpikeArbStock.SpikeArbCollar.Collar1, (double)collar1Percent, (double)collar1Value, (double)collar1Window);
                    if (collar1Enabled)
                        strategy.Collar1.IsEnabled = strategy.ToggleCollar(SpikeArbStock.SpikeArbCollar.Collar1);

                    strategy.SetCollar(SpikeArbStock.SpikeArbCollar.Collar2, (double)collar2Percent, (double)collar2Value, (double)collar2Window);
                    if (collar2Enabled)
                        strategy.Collar2.IsEnabled = strategy.ToggleCollar(SpikeArbStock.SpikeArbCollar.Collar2);

                    strategy.SetCollar(SpikeArbStock.SpikeArbCollar.Collar3, (double)collar3Percent, (double)collar3Value, (double)collar3Window);
                    if (collar3Enabled)
                        strategy.Collar3.IsEnabled = strategy.ToggleCollar(SpikeArbStock.SpikeArbCollar.Collar3);

                    strategy.SetCollar(SpikeArbStock.SpikeArbCollar.Collar4, (double)collar4Percent, (double)collar4Value, (double)collar4Window);
                    if (collar4Enabled)
                        strategy.Collar4.IsEnabled = strategy.ToggleCollar(SpikeArbStock.SpikeArbCollar.Collar4);

                    return strategy;
                },
                (inStock, inStrategy) =>
                {
                    strategy = inStrategy;

                    strategy.ListingPrimary.IsEnabled = isEnabledPrimary;
                    strategy.ListingChix.IsEnabled = isEnabledChix;
                    strategy.ListingBats.IsEnabled = isEnabledBATE;

                    strategy.SetCollar(SpikeArbStock.SpikeArbCollar.Collar1, (double)collar1Percent, (double)collar1Value, (double)collar1Window);
                    if (collar1Enabled)
                        strategy.Collar1.IsEnabled = strategy.ToggleCollar(SpikeArbStock.SpikeArbCollar.Collar1);

                    strategy.SetCollar(SpikeArbStock.SpikeArbCollar.Collar2, (double)collar2Percent, (double)collar2Value, (double)collar2Window);
                    if (collar2Enabled)
                        strategy.Collar2.IsEnabled = strategy.ToggleCollar(SpikeArbStock.SpikeArbCollar.Collar2);

                    strategy.SetCollar(SpikeArbStock.SpikeArbCollar.Collar3, (double)collar3Percent, (double)collar3Value, (double)collar3Window);
                    if (collar3Enabled)
                        strategy.Collar3.IsEnabled = strategy.ToggleCollar(SpikeArbStock.SpikeArbCollar.Collar3);

                    strategy.SetCollar(SpikeArbStock.SpikeArbCollar.Collar4, (double)collar4Percent, (double)collar4Value, (double)collar4Window);
                    if (collar4Enabled)
                        strategy.Collar4.IsEnabled = strategy.ToggleCollar(SpikeArbStock.SpikeArbCollar.Collar4);

                    return strategy;
                });

            // add the strategy to the viewer
            if (ViewSettings != null)
            {
                strategy.View = ViewSettings.AddOrUpdate(strategy.Stock.Symbol,
                    (key) =>
                    {
                        return new SpikeArbStockView(strategy);
                    },
                    (key, value) =>
                    {
                        return new SpikeArbStockView(strategy);
                    });
            }
            return strategy;
        }
        
        public void RemoveAll()
        {
            Strategies.Clear();
            if (ViewSettings != null)
            {
                ViewSettings.Clear();
            }
        }

        internal void InsertExecution(SpikeArbFill fill)
        {
            ((ConcurrentObservableCollection<SpikeArbFill>)ViewExecutions.SourceCollection).Add(fill);
        }

        public void StopStrategy()
        {
            PauseStrategy(Pause.Primary);
            PauseStrategy(Pause.Chix);
            PauseStrategy(Pause.Bats);
        }

        public void StopStrategy(object caller)
        {
            StopStrategy();
        }

        public void PauseStrategy(Pause type)
        {
            Strategies.Values.ToList().ForEach(ss => ss.PauseStrategy(type));
        }

        //void MarketFeed_OnPriceBBO(IStock stock, Objects.Finance.Prices.PriceVolume bid, Objects.Finance.Prices.PriceVolume ask)
        //{
        //    SpikeArbStock arb;
        //    if (stock is StockSecurity && Strategies.TryGetValue((StockSecurity)stock, out arb))
        //    {
        //        arb.OnPriceBBO(bid, ask);
        //    }
        //}


        #endregion
        //////////
        #region Enums
        
        public enum Pause
        {
            Chix,
            Bats,
            Primary,
            Collar1,
            Collar2,
            Collar3,
            Collar4
        }

        #endregion

    }
}
